package com.projectxxxxxxxxxx.report;

import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

import android.Manifest.permission;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.StatFs;
import android.telephony.TelephonyManager;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import com.projectxxxxxxxxxx.Constants;
import com.projectxxxxxxxxxx.RoboApplication;

public class ErrorReporter implements Thread.UncaughtExceptionHandler {

    Thread.UncaughtExceptionHandler oldHandler;

    public ErrorReporter() {
        // сохраним ранее установленный обработчик
        oldHandler = Thread.getDefaultUncaughtExceptionHandler();
    }

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {

        try {
            Log.d("TryMe", "Something wrong happened! Send Report!");
            // sendMail(getReport());

        } catch (Exception e) {
            Log.e(Constants.LOG_TAG, e.getMessage(), e);
        } catch (OutOfMemoryError e) {
            Log.e(Constants.LOG_TAG, e.getMessage(), e);
        }

        if (oldHandler != null)
            oldHandler.uncaughtException(thread, throwable);

    }

    public void sendMail(final Map errorInfo) {

        // MailSenderClass sender = new MailSenderClass("evgenaia@gmail.com",
        // "29071989aia");

        try {
            String app_name = (String) errorInfo.get(ReportField.APP_VERSION_NAME);
            String phone_model = (String) errorInfo.get(ReportField.PHONE_MODEL);
            String dev_id = (String) errorInfo.get(ReportField.DEVICE_ID);

            TelephonyManager mTelephonyMgr = (TelephonyManager) RoboApplication.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
            String imsi = mTelephonyMgr.getSubscriberId();
            String imei = mTelephonyMgr.getDeviceId();
            String dev_id_tel = "" + new Random().nextLong();
            if (imsi != null) {
                dev_id_tel = imsi;
            } else if (imei != null) {
                dev_id_tel = imei;
            }

            if (dev_id.equals(""))
                dev_id = dev_id_tel;

            // sender.sendMail("Robo bug report. " +
            // "Version = " + app_name + " " +
            // "Model = " + phone_model + " " +
            // "ID = " + dev_id, errorInfo.toString(), "evgenaia@gmail.com",
            // "evgenaia@gmail.com");

            // Log.e(Constants.LOG_TAG, "Robo bug report. " +
            // "Version = " + app_name + " " +
            // "Model = " + phone_model + " " +
            // "ID = " + dev_id);

        } catch (Exception e) {
            Log.e(Constants.LOG_TAG, e.getMessage(), e);
        }
    }

    public final static ReportField[] DEFAULT_MAIL_REPORT_FIELDS = {
            ReportField.ANDROID_VERSION, ReportField.APP_VERSION_NAME, ReportField.PHONE_MODEL
    };

    /**
     * Default list of {@link ReportField}s to be sent in reports. You can set
     * your own list with {@link ReportsCrashes#reportFields()}.
     */
    public static final ReportField[] DEFAULT_REPORT_FIELDS = {
            ReportField.REPORT_ID, ReportField.APP_VERSION_CODE,
            ReportField.APP_VERSION_NAME, ReportField.PACKAGE_NAME, ReportField.FILE_PATH, ReportField.PHONE_MODEL,
            ReportField.BRAND, ReportField.PRODUCT, ReportField.ANDROID_VERSION, ReportField.TOTAL_MEM_SIZE,
            ReportField.AVAILABLE_MEM_SIZE,
            ReportField.DISPLAY,
            ReportField.USER_CRASH_DATE,
            ReportField.DEVICE_ID, ReportField.INSTALLATION_ID

    };

    public Map getReport() {
        Map<ReportField, String> mCrashProperties = new HashMap<ReportField, String>();

        try {
            ReportField[] fields = DEFAULT_MAIL_REPORT_FIELDS;

            List<ReportField> fieldsList = Arrays.asList(fields);


            // Generate report uuid
            if (fieldsList.contains(ReportField.REPORT_ID)) {
                mCrashProperties.put(ReportField.REPORT_ID, UUID.randomUUID().toString());
            }

            PackageManager pm = RoboApplication.getInstance().getPackageManager();

            // Collect DropBox and logcat
            if (pm != null) {
                // Retrieve UDID(IMEI) if permission is available
                if (fieldsList.contains(ReportField.DEVICE_ID)
                        && pm.checkPermission(permission.READ_PHONE_STATE, RoboApplication.getInstance().getPackageName()) == PackageManager.PERMISSION_GRANTED) {
                    TelephonyManager tm = (TelephonyManager) RoboApplication.getInstance().getSystemService(Context.TELEPHONY_SERVICE);
                    String deviceId = tm.getDeviceId();
                    if (deviceId != null) {
                        mCrashProperties.put(ReportField.DEVICE_ID, deviceId);
                    }
                }
            }

            PackageInfo pi;
            pi = pm.getPackageInfo(RoboApplication.getInstance().getPackageName(), 0);
            if (pi != null) {
                // Application Version
                if (fieldsList.contains(ReportField.APP_VERSION_CODE)) {
                    mCrashProperties.put(ReportField.APP_VERSION_CODE, Integer.toString(pi.versionCode));
                }
                if (fieldsList.contains(ReportField.APP_VERSION_NAME)) {
                    mCrashProperties.put(ReportField.APP_VERSION_NAME, pi.versionName != null ? pi.versionName : "not set");
                }
            } else {
                // Could not retrieve package info...
                mCrashProperties.put(ReportField.APP_VERSION_NAME, "Package info unavailable");
            }

            // Application Package name
            if (fieldsList.contains(ReportField.PACKAGE_NAME)) {
                mCrashProperties.put(ReportField.PACKAGE_NAME, RoboApplication.getInstance().getPackageName());
            }


            // Device model
            if (fieldsList.contains(ReportField.PHONE_MODEL)) {
                mCrashProperties.put(ReportField.PHONE_MODEL, android.os.Build.MODEL);
            }
            // Android version
            if (fieldsList.contains(ReportField.ANDROID_VERSION)) {
                mCrashProperties.put(ReportField.ANDROID_VERSION, android.os.Build.VERSION.RELEASE);
            }

            // Device Brand (manufacturer)
            if (fieldsList.contains(ReportField.BRAND)) {
                mCrashProperties.put(ReportField.BRAND, android.os.Build.BRAND);
            }
            if (fieldsList.contains(ReportField.PRODUCT)) {
                mCrashProperties.put(ReportField.PRODUCT, android.os.Build.PRODUCT);
            }

            // Device Memory
            if (fieldsList.contains(ReportField.TOTAL_MEM_SIZE)) {
                mCrashProperties.put(ReportField.TOTAL_MEM_SIZE, Long.toString(getTotalInternalMemorySize()));
            }
            if (fieldsList.contains(ReportField.AVAILABLE_MEM_SIZE)) {
                mCrashProperties.put(ReportField.AVAILABLE_MEM_SIZE, Long.toString(getAvailableInternalMemorySize()));
            }

            // Application file path
            if (fieldsList.contains(ReportField.FILE_PATH)) {
                mCrashProperties.put(ReportField.FILE_PATH, RoboApplication.getInstance().getFilesDir().getAbsolutePath());
            }

            // Main display details
            if (fieldsList.contains(ReportField.DISPLAY)) {
                Display display = ((WindowManager) RoboApplication.getInstance().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
                mCrashProperties.put(ReportField.DISPLAY, toString(display));
            }

            // User crash date with local timezone
            if (fieldsList.contains(ReportField.USER_CRASH_DATE)) {
                Time curDate = new Time();
                curDate.setToNow();
                mCrashProperties.put(ReportField.USER_CRASH_DATE, curDate.format3339(false));
            }

        } catch (Exception e) {
            Log.e(Constants.LOG_TAG, "Error while retrieving crash data", e);
        }
        return mCrashProperties;
    }
    
    private static long getAvailableInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    }

    private static long getTotalInternalMemorySize() {
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
        return totalBlocks * blockSize;
    }

    private static String toString(Display display) {
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        StringBuilder result = new StringBuilder();
        result.append("width=").append(display.getWidth()).append('\n').append("height=").append(display.getHeight())
                .append('\n').append("pixelFormat=").append(display.getPixelFormat()).append('\n')
                .append("refreshRate=").append(display.getRefreshRate()).append("fps").append('\n')
                .append("metrics.density=x").append(metrics.density).append('\n').append("metrics.scaledDensity=x")
                .append(metrics.scaledDensity).append('\n').append("metrics.widthPixels=").append(metrics.widthPixels)
                .append('\n').append("metrics.heightPixels=").append(metrics.heightPixels).append('\n')
                .append("metrics.xdpi=").append(metrics.xdpi).append('\n').append("metrics.ydpi=").append(metrics.ydpi);

        return result.toString();
    }

}










